package cn.yeziji.file.service.impl;

import cn.yeziji.file.basic.FileProcess;
import cn.yeziji.file.basic.MinioProperties;
import cn.yeziji.file.converter.FileConverter;
import cn.yeziji.file.dto.FileDTO;
import cn.yeziji.file.service.FileService;
import cn.yeziji.file.service.InteractionService;
import cn.yeziji.file.utils.FileHandlerUtils;
import cn.yeziji.file.vo.FileDataVO;
import cn.yeziji.file.vo.FileVO;
import cn.yeziji.forum.basic.file.DirectUploaderFilesInfo;
import cn.yeziji.forum.basic.file.OssRequiredEntry;
import cn.yeziji.forum.basic.file.WebUploader;
import cn.yeziji.forum.basic.file.WebUploaderFileInfo;
import cn.yeziji.forum.basic.pay.PayPathInfo;
import cn.yeziji.forum.common.AliCloudOss;
import cn.yeziji.forum.common.ForumPageResult;
import cn.yeziji.forum.common.enums.ForumCommonStatus;
import cn.yeziji.forum.common.enums.PayFilePrefixEnum;
import cn.yeziji.forum.common.enums.status.FileStatus;
import cn.yeziji.forum.common.enums.status.PayStatus;
import cn.yeziji.forum.common.key.CommonKey;
import cn.yeziji.forum.common.key.FileCacheKey;
import cn.yeziji.forum.dto.file.ForumFilePagingDTO;
import cn.yeziji.forum.dto.pay.path.WechatPathDTO;
import cn.yeziji.forum.dubbo.OpenFileService;
import cn.yeziji.forum.entity.ForumUserEntity;
import cn.yeziji.forum.exception.FileException;
import cn.yeziji.forum.exception.ForumException;
import cn.yeziji.forum.exception.PayException;
import cn.yeziji.forum.service.UploadFileService;
import cn.yeziji.forum.utils.*;
import cn.yeziji.forum.utils.entity.AliOssConfig;
import cn.yzj.common.CommonSymbol;
import cn.yzj.entity.MinioFileEntity;
import cn.yzj.utils.DataUtils;
import cn.yzj.utils.MinioOperaUtils;
import com.alibaba.dubbo.config.annotation.Service;
import com.github.benmanes.caffeine.cache.Cache;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.cert.CertificateException;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 文件服务实现类
 *
 * @author gzkemays
 * @since 2022/5/12 8:36
 */
@Service(interfaceClass = OpenFileService.class)
@Component
@Slf4j
public class FileServiceImpl implements FileService, OpenFileService {

  @Resource AliCloudOss oss;
  @Resource CacheUtils cacheUtils;
  @Resource MinioProperties properties;
  @Resource InteractionService interactionService;
  RedisTemplate<String, Object> redisTemplate;
  @Resource(name="fileCache")
  Cache<String, Object> caffeineCache;
  MinioOperaUtils minio;
  @Value("${pay.fileRootPath}")
  String fileRootPath;

  @PostConstruct
  public void init() {
    minio =
        new MinioOperaUtils(
            properties.getAccessKey(), properties.getSecretKey(), properties.getEndpoint());
    cacheUtils.newCaffeineCache(caffeineCache).caffeineAddTime(1, TimeUnit.MINUTES);
    redisTemplate = cacheUtils.getRedisTemplate();
  }

  @Override
  public Integer getProcess(String md5) {
    String username = interactionService.getUsernameByToken();
    WebUploader.ChuckEntity entity =
        cacheUtils.getHashValues(uploadCacheKey(md5, username)).stream()
            .map(chunk -> (WebUploader.ChuckEntity) chunk)
            .max(Comparator.comparing(WebUploader.ChuckEntity::getChunk))
            .orElse(null);

    if (entity == null) {
      return interactionService.getProcess(md5);
    }
    return entity.getChunk();
  }

  @Override
  public boolean locationUploader(WebUploader uploader) {
    // 校验上传码是否为空
    String uploadCode = uploader.getUploadCode();
    ForumUserEntity userEntityByToken = interactionService.getUserEntityByToken();
    // 低于 30 级的用户才需要上传码
    if (Integer.parseInt(userEntityByToken.getLevel()) < 30 && !checkUploadCode(uploadCode)) {
      return false;
    }
    // 查看分片大小是否 <= 指定分片大小
    MultipartFile file = uploader.getFile();
    long size = file.getSize();
    if (size > CHUNK_SIZE) {
      throw new FileException(FileStatus.CHUNK_SIZE_VALIDATE_FAIL);
    }
    // 读取文件路径、用户名、文件名、文件MD5 等基础数据
    String path = Optional.ofNullable(uploader.getPath()).orElse("forum"),
        username = interactionService.getUsernameByToken(),
        originalFilename = file.getOriginalFilename(),
        uploaderMd5 = uploader.getMd5();
    // 获取分片信息
    Integer chunks = uploader.getChunks(), chunk = uploader.getChunk();
    Long allSize = uploader.getSize();
    boolean validate = false;
    // 意味着不用分片
    if (chunk == null) {
      chunk = 0;
      chunks = 1;
    }
    // 获取文件保存路径
    StringJoiner sj = new StringJoiner(File.separator);
    sj.add(properties.getSavePath()).add(path).add(originalFilename);
    String filePath = sj.toString();
    File saveFile;
    // 单线程文件续写
    try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
      if (!(saveFile = new File(filePath)).exists()) {
        saveFile.getParentFile().mkdirs();
        saveFile.createNewFile();
      }
      raf.seek(chunk * CHUNK_SIZE);
      raf.write(file.getBytes());
      // 写入文件后保存上传进度
      WebUploader.ChuckEntity chuckEntity =
          new WebUploader.ChuckEntity(
              uploaderMd5,
              chunks,
              chunk,
              username,
              path,
              allSize,
              originalFilename,
              uploader.getDesc());
      // 保存进度进 cache
      cacheUtils.setHash(
          uploadCacheKey(uploaderMd5, username),
          String.valueOf(chunk),
          chuckEntity,
          3,
          TimeUnit.DAYS);
      // 更新校验状态
      synchronized (this) {
        boolean check = checkUpload(chuckEntity, filePath);
        if (check) {
          updateUploadCode(uploadCacheKey(uploaderMd5, username), uploadCode);
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    return validate;
  }

  @Override
  public boolean ossUploader(WebUploader uploader) {
    MultipartFile file = uploader.getFile();
    // 获取分片
    Integer chunk = uploader.getChunk(), chunks = uploader.getChunks();
    // 用户名
    String username = interactionService.getUsernameByToken();
    // 意味着不用分片
    if (chunk == null) {
      chunk = 0;
      chunks = 1;
    }
    String filePath = properties.getSavePath() + File.separator + file.getOriginalFilename();
    try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
      ByteBuffer buffer = ByteBuffer.allocate(file.getBytes().length);
      buffer.put(file.getBytes());
      FileChannel channel = raf.getChannel();
      buffer.flip();
      while (buffer.hasRemaining()) {
        channel.write(buffer, chunk * CHUNK_SIZE);
      }
      // 上传写入之后，保存上传的进度
      String md5 = uploader.getMd5(),
          filename = file.getOriginalFilename(),
          desc = uploader.getDesc();
      Long size = uploader.getSize();
      WebUploader.ChuckEntity chuckEntity =
          new WebUploader.ChuckEntity(
              md5, chunks, chunk, username, uploader.getPath(), size, filename, desc);
      // 保存进度进 cache
      cacheUtils.setHash(
          uploadCacheKey(md5, username), String.valueOf(chunk), chuckEntity, 3, TimeUnit.DAYS);
      // 同步逐个更新校验状态
      synchronized (this) {
        checkUpload(chuckEntity, filePath);
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    return false;
  }

  public void updateUploadCode(String key, String uploadCode) {
    redisTemplate
        .opsForZSet()
        .incrementScore(FileCacheKey.FILE_CACHE_PREFIX + "::UploadCode", uploadCode, 1);
    // 重设缓存时间，删除一级缓存。
    redisTemplate.expire(key, 5, TimeUnit.SECONDS);
  }

  boolean checkUpload(WebUploader.ChuckEntity chuckEntity, String filePath) {
    String uploaderMd5 = chuckEntity.getUploaderMd5(), username = chuckEntity.getUsername();
    Integer chunks = chuckEntity.getChunks();
    // 上传完毕校验文件 MD5
    // 前端开启了5个线程，线程 chunk 数 - 5后开始校验。
    boolean validate;
    // 不能根据前端传入的 chunk 来判断，需要根据缓存中的值进行判断
    if (cacheUtils.getHashMaps(uploadCacheKey(uploaderMd5, username)).size() == chunks) {
      try {
        FileInputStream fileInputStream = new FileInputStream(ResourceUtils.getFile(filePath));
        String cacheKey = uploadCacheKey(uploaderMd5, username);
        String md5 = DigestUtils.md5DigestAsHex(fileInputStream);
        validate = md5.equals(uploaderMd5);
        fileInputStream.close();
        if (!validate) {
          cacheUtils.remove(cacheKey);
          throw new FileException(FileStatus.FILE_VALIDATE_FAIL);
        } else {
          // 文件校验成功
          log.info("文件校验成功 -> {}", chuckEntity.getOriginalFilename());
          redisTemplate.expire(cacheKey, 5, TimeUnit.SECONDS);
          return true;
        }
      } catch (IOException e) {
        e.printStackTrace();
      } finally {
        // 清除上传记录
        caffeineCache.invalidate(uploaderMd5);
      }
    }
    return false;
  }

  @Override
  public FileVO getFile(FileDTO file) {
    String filename = file.getFilename();
    if (StringUtils.isBlank(filename)) {
      throw new ForumException(ForumCommonStatus.DATA_ERROR);
    }
    String cacheKey = getCacheKey(filename);
    FileVO object = cacheUtils.get(cacheKey);
    MinioFileEntity fileEntity;
    if (object == null) {
      if ((fileEntity =
                  minio.getFileEntity(
                      MinioFileEntity.builder()
                          .bucketName(file.getRootPath())
                          .fileName(filename)
                          .build()))
              .getAccessUrl()
          != null) {

        FileVO fileVO = FileConverter.INSTANCE.minioFileEntityConvertToFileVO(fileEntity);
        String accessUrl = fileVO.getAccessUrl();
        fileVO.setAccessUrl(accessUrl.replace(properties.getEndpoint(),"http://minio.yeziji.xyz"));
        cacheUtils.set(cacheKey, fileVO, 1, TimeUnit.DAYS);
        return fileVO;
      }
      throw new FileException(FileStatus.FILE_NAME_IS_NULL);
    } else {
      return object;
    }
  }

  @Override
  public List<FileVO> getFiles(FileDTO file) {
    if (StringUtils.isBlank(file.getRootPath())) {
      throw new ForumException(ForumCommonStatus.DATA_ERROR);
    }
    // 遍历所有上传缓存记录
    List<Map<Object, Object>> blurHashMap =
        cacheUtils.getBlurHashMap(FileCacheKey.FILE_UPLOAD_CACHE);
    List<String> cacheFilter = new ArrayList<>();
    Map<String, String> sourceMap = new HashMap<>();
    for (Map<Object, Object> map : blurHashMap) {
      // 获取到每个记录中上传的最大分片
      WebUploaderFileInfo maxInfo = FileHandlerUtils.getMaxFileInfoByMap(map);
      // 可能会空
      if (maxInfo == null) {
        continue;
      }
      String filename = maxInfo.getFilename();
      int chunks = maxInfo.getChunks(), chunk = maxInfo.getChunk();
      // 过滤出未分片未上传完整的数据
      if (chunk < chunks) {
        cacheFilter.add(filename);
      } else {
        String source = maxInfo.getUsername();
        sourceMap.put(filename, source);
      }
    }
    // 筛选掉未上传完毕的文件
    List<MinioFileEntity> bucketFileList =
        minio.getBucketFileList(file.getRootPath()).stream()
            .filter(entity -> !cacheFilter.contains(entity.getFileName()))
            .collect(Collectors.toList());
    // TODO: 获取贡献者
    // minio 的文件名
    /*    List<String> filesName =
    bucketFileList.stream().map(MinioFileEntity::getFileName).collect(Collectors.toList());*/

    return FileConverter.INSTANCE.minioFileEntitiesConvertToFileVOS(bucketFileList).stream()
        .peek(
            vo -> {
              String source = sourceMap.get(vo.getFileName());
              vo.setSource(StringUtils.isBlank(source) ? "管理员" : source);
            })
        .sorted(
            (vo1, vo2) -> {
              String updateTime = vo1.getUpdateTime();
              String updateTime1 = vo2.getUpdateTime();
              Boolean rightLong =
                  TimeUtils.compareTime(updateTime, updateTime1, "yyyy-MM-dd HH:mm:ss");
              return rightLong ? -1 : (Objects.equals(updateTime, updateTime1) ? 0 : 1);
            })
        .collect(Collectors.toList());
  }

  @Override
  public ForumPageResult<FileDataVO> getDataFiles(ForumFilePagingDTO dto) {
    return interactionService.getFileEntitiesPage(dto);
  }

  @Override
  public List<FileProcess> getUserFiles() {
    String username = interactionService.getUsernameByToken();
    // 获取缓存中未上传完毕的数据
    List<Map<Object, Object>> blurHashMap =
        cacheUtils.getBlurHashMap(FileCacheKey.FILE_UPLOAD_CACHE + "::", username);
    List<FileProcess> cacheProcess = getFilesProcess(blurHashMap);
    List<FileProcess> sqlProcess =
        FileConverter.INSTANCE.forumFileEntitiesConvertToFilesProcess(
            interactionService.getFileEntitiesBySource());
    cacheProcess.addAll(sqlProcess);
    return cacheProcess;
  }

  @Override
  public List<String> getCodes(Integer num) {
    int integer = Optional.ofNullable(num).orElse(1);
    List<String> codes = new ArrayList<>();
    RedisTemplate<String, Object> redisTemplate = cacheUtils.getRedisTemplate();
    for (int i = 0; i < integer; i++) {
      String code = NanoIdUtils.randomNaoId(8);
      redisTemplate.opsForZSet().add(FileCacheKey.FILE_CACHE_PREFIX + "::UploadCode", code, 0);
      codes.add(code);
    }
    return codes;
  }

  @Override
  public List<String> searchCodes() {
    RedisTemplate<String, Object> redisTemplate = cacheUtils.getRedisTemplate();
    Set<Object> objects =
        redisTemplate
            .opsForZSet()
            .rangeByScore(FileCacheKey.FILE_CACHE_PREFIX + "::UploadCode", 0, 5);
    assert objects != null;
    return objects.stream().map(String::valueOf).collect(Collectors.toList());
  }

  @Override
  public String oss(OssRequiredEntry entry) {
    return AliUtils.uploadToOss(
        AliOssConfig.cloudOss(oss)
            .savePath(entry.getSavePath())
            .fileName(entry.getFilename())
            .stream(entry.getStream())
            .build());
  }

  @Override
  public List<String> directCloud(DirectUploaderFilesInfo filesInfo) {
    List<UploadFileService.FileUploadStatus> fileUploadStatuses = checkFilesExists(filesInfo);
    String path = filesInfo.getPath();
    if (filesInfo.length() > THREAD_NUM) {
      return threadUpload(fileUploadStatuses, path);
    } else {
      return singleUpload(fileUploadStatuses, path);
    }
  }

  @Override
  public boolean deleteFile(FileDTO dto) {
    String tmp = dto.getFilename(), filename;
    if (tmp.contains(CommonSymbol.STAR_SIGN)) {
      dto.setFilename(filename = DataUtils.substrBeforeOfTag(tmp, CommonSymbol.STAR_SIGN));
    } else {
      filename = tmp;
    }
    if (getFile(dto) == null) {
      return false;
    }
    try {
      minio.deleteFile(
          MinioFileEntity.builder().bucketName(dto.getRootPath()).fileName(filename).build());
      interactionService.del(tmp);
      return true;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return false;
  }

  @Override
  public PayPathInfo getMerchantPayFilePath(@NotNull Integer userId, @NotNull PayFilePrefixEnum payFilePrefixEnum) {
    try {
      if (Objects.equals(payFilePrefixEnum, PayFilePrefixEnum.WECHAT)) {
        WechatPathDTO wechatPathDTO = new WechatPathDTO();
        // 记录不存在的文件
        List<String> recordNotExistsFiles = new ArrayList<>();
        // 获取文件的相路径；
        String[] requiredFiles = payFilePrefixEnum.getRequiredFiles();
        for (String requiredFile : requiredFiles) {
          // 先查看本地是否存在
          String relativeFilePath = payFilePrefixEnum.getUserRelativePayPrefixPath(fileRootPath, userId) + File.separator + requiredFile;
          File file = new File(relativeFilePath);
          if (!file.exists()) {
            // 不存在就拼接 oss 的用户路径去获取
            log.info("本地不存在 -> {}", requiredFile);
            recordNotExistsFiles.add(requiredFile);
          } else {
            // 存在就映射路径
            log.info("本地存在 -> {}, 路径为 -> {}", requiredFile, relativeFilePath);
            wechatPathDTO.mappingPath(requiredFile, relativeFilePath);
          }
        }
        // 下载保存文件
        if (!recordNotExistsFiles.isEmpty()) {
          for (String recordNotExistsFile : recordNotExistsFiles) {
            CompletableFuture<TempSavePathInfo> downloadFilePaths = CompletableFuture.supplyAsync(() -> {
              AliOssConfig ossConfig = AliOssConfig.cloudPayOss(oss)
                  .savePath(payFilePrefixEnum.getUserOssPaySavePath(userId))
                  .localPath(payFilePrefixEnum.getUserRelativePayPrefixPath(fileRootPath, userId))
                  .fileName(recordNotExistsFile)
                  .build();
              String filename = AliUtils.saveFile(ossConfig);
              return new TempSavePathInfo(filename, ossConfig.getLocalFilePath());
            }, ThreadPoolUtils.getIoThreadPool());
            // 文件很小，每次保存只等待 30 秒
            TempSavePathInfo tempSavePathInfo = downloadFilePaths.get(30, TimeUnit.SECONDS);
            wechatPathDTO.mappingPath(tempSavePathInfo.getFileName(), tempSavePathInfo.getFilePath());
          }
        }
        return wechatPathDTO;
      }
    } catch (ExecutionException | InterruptedException | TimeoutException e) {
      log.error("获取配置异常 -> {}", e.getMessage(), e);
      throw new PayException(PayStatus.USER_NO_SUPPORT_PAY);
    }
    throw new PayException(PayStatus.NO_SUPPORT_PAY_TYPE);
  }

  /**
   * 多线程上传文件
   *
   * @param files 文件列表
   * @param path 上传的目录
   * @return 上传地址
   */
  private List<String> threadUpload(List<UploadFileService.FileUploadStatus> files, String path) {
    List<String> urls = new ArrayList<>();
    List<Future<String>> futures = new ArrayList<>();
    ThreadPoolConfigUtils.builder()
        .createThreadPool()
        .corePoolSize(3)
        .maximumPoolSize(6)
        .operation(
            (e) -> {
              for (UploadFileService.FileUploadStatus file : files) {
                Future<String> submit =
                    e.submit(
                        () -> {
                          if (!file.isUpload()) {
                            MultipartFile f = file.getFile();
                            String filename = buildMd5Filename(f);
                            OssRequiredEntry ossRequiredEntry =
                                new OssRequiredEntry(path, filename, f.getInputStream());
                            String url = oss(ossRequiredEntry);
                            cacheUtils.set(
                                FileCacheKey.FILE_UPLOAD_CACHE + "::" + filename,
                                url,
                                7,
                                TimeUnit.DAYS);
                            return url;
                          } else {
                            return file.getUrl();
                          }
                        });
                futures.add(submit);
              }
            })
        .build();
    futures.forEach(
        future -> {
          try {
            urls.add(future.get());
          } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
          }
        });
    return urls;
  }

  /**
   * 单线程上传文件
   *
   * @param files 文件列表
   * @param path 上传的目录
   * @return 上传的地址
   */
  private List<String> singleUpload(List<UploadFileService.FileUploadStatus> files, String path) {
    List<String> urls = new ArrayList<>();
    for (UploadFileService.FileUploadStatus file : files) {
      if (!file.isUpload()) {
        MultipartFile f = file.getFile();
        try {
          String filename = buildMd5Filename(f);
          OssRequiredEntry ossRequiredEntry =
              new OssRequiredEntry(path, filename, f.getInputStream());
          String url = oss(ossRequiredEntry);
          cacheUtils.set(FileCacheKey.FILE_UPLOAD_CACHE + "::" + filename, url, 7, TimeUnit.DAYS);
          urls.add(url);
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      } else {
        urls.add(file.getUrl());
      }
    }
    return urls;
  }

  private List<UploadFileService.FileUploadStatus> checkFilesExists(
      DirectUploaderFilesInfo directUploaderFilesInfo) {
    List<UploadFileService.FileUploadStatus> urls = new ArrayList<>();
    MultipartFile[] files = directUploaderFilesInfo.getFiles();
    String path = directUploaderFilesInfo.getPath();
    for (MultipartFile file : files) {
      try {
        String filename = buildMd5Filename(file);
        String ifPresent = cacheUtils.get(FileCacheKey.FILE_UPLOAD_CACHE + "::" + filename);
        if (ifPresent != null) {
          urls.add(new UploadFileService.FileUploadStatus(filename, ifPresent, true, file));
        } else {
          // 可能缓存过期
          String expectUrl = UPLOAD_PREFIX + path + "/" + buildMd5Filename(file);
          log.info("expect url --> {}", expectUrl);
          URL url = new URL(expectUrl);
          trustAllHosts();
          // 发送请求进行判断
          HttpURLConnection connection = (HttpURLConnection) url.openConnection();
          connection.setRequestMethod("GET");
          connection.setUseCaches(false);
          connection.setDoOutput(true);
          connection.setDoInput(true);
          int responseCode = connection.getResponseCode();
          if (responseCode == HttpURLConnection.HTTP_OK) {
            urls.add(new UploadFileService.FileUploadStatus(filename, expectUrl, true, file));
          } else {
            urls.add(new UploadFileService.FileUploadStatus(filename, null, false, file));
          }
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return urls;
  }

  /**
   * 获取文件进度状态
   *
   * @param blurHashMap 筛选的数据
   * @return 状态文件列表
   */
  private List<FileProcess> getFilesProcess(List<Map<Object, Object>> blurHashMap) {
    List<FileProcess> vos = new ArrayList<>();
    for (Map<Object, Object> map : blurHashMap) {
      FileProcess fileProcess = new FileProcess();
      // 可能会空
      WebUploaderFileInfo maxInfo = FileHandlerUtils.getMaxFileInfoByMap(map);
      if (maxInfo == null) {
        continue;
      }
      String filename = maxInfo.getFilename(), username = maxInfo.getUsername();
      long size = maxInfo.getSizeByte();
      int chunks = maxInfo.getChunks(), chunk = maxInfo.getChunk();
      fileProcess.setUsername(username);
      fileProcess.setFilename(filename);
      fileProcess.setSize(size);
      // 过滤出未分片未上传完整的数据
      fileProcess.setChunk(chunk);
      fileProcess.setChunks(chunks);
      if (chunk < chunks) {
        fileProcess.setStatus(FileProcess.UN_UPLOAD);
        fileProcess.mathProcess(chunk, chunks);
      } else {
        fileProcess.setStatus(FileProcess.END_UPLOAD);
      }
      vos.add(fileProcess);
    }
    return vos;
  }

  private String buildMd5Filename(MultipartFile file) {
    try {
      String md5 = DigestUtils.md5DigestAsHex(file.getInputStream());
      String ext = StrUtils.getLastSplitHasSplitAfterStr(file.getOriginalFilename(), CommonKey.DOT);
      return md5 + ext;
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  private void trustAllHosts() {
    TrustManager[] trustAllCerts =
        new TrustManager[] {
          new X509TrustManager() {
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
              return new java.security.cert.X509Certificate[] {};
            }

            @Override
            public void checkClientTrusted(
                java.security.cert.X509Certificate[] chain, String authType)
                throws CertificateException {}

            @Override
            public void checkServerTrusted(
                java.security.cert.X509Certificate[] chain, String authType)
                throws CertificateException {}
          }
        };

    // Install the all-trusting trust manager
    try {
      SSLContext sc = SSLContext.getInstance("SSL", "SunJSSE");
      sc.init(null, trustAllCerts, new java.security.SecureRandom());
      HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
      HttpsURLConnection.setDefaultHostnameVerifier(NoopHostnameVerifier.INSTANCE);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @Data
  @NoArgsConstructor
  @AllArgsConstructor
  static class TempSavePathInfo {
    private String fileName;
    private String filePath;
  }
}
